package com.simple.tools.aab2apks;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;

public class MainController {
    private static final Logger logger = LoggerFactory.getLogger(MainController.class);

    @FXML private TextField aabFilePathField;
    @FXML private TextField outputDirPathField;
    @FXML private ComboBox<String> bundletoolVersionComboBox;
    @FXML private TextField deviceSpecField;
    @FXML private Button convertButton;
    @FXML private ProgressBar progressBar;
    @FXML private TextArea logArea;
    @FXML private CheckBox universalApkCheckBox;
    @FXML private TextField keystorePathField;
    @FXML private PasswordField keystorePasswordField;
    @FXML private ComboBox<String> keyAliasComboBox;
    @FXML private PasswordField keyPasswordField;

    private File aabFile;
    private File outputDir;
    private File bundletoolJar;
    private File deviceSpecFile;
    private File keystoreFile;
    private File bundletoolDownloadDir;

    private static final List<String> BUNDLETOOL_VERSIONS = Arrays.asList("1.11.0", "1.10.0", "1.9.0", "1.8.0", "1.7.0");
    private static final String SETTINGS_FILE = "settings.properties";

    @FXML
    private void initialize() {
        convertButton.setDisable(true);
        bundletoolVersionComboBox.getItems().addAll(BUNDLETOOL_VERSIONS);
        bundletoolVersionComboBox.setValue(BUNDLETOOL_VERSIONS.get(0));
        universalApkCheckBox.setSelected(true);

        loadSettings();

        keystorePathField.textProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue.isEmpty()) {
                loadKeyAliases(new File(newValue), keystorePasswordField.getText());
            }
        });

        keystorePasswordField.textProperty().addListener((observable, oldValue, newValue) -> {
            if (!keystorePathField.getText().isEmpty()) {
                loadKeyAliases(new File(keystorePathField.getText()), newValue);
            }
        });
    }

    private void loadSettings() {
        Properties settings = new Properties();
        try (InputStream input = new FileInputStream(SETTINGS_FILE)) {
            settings.load(input);
            bundletoolDownloadDir = new File(settings.getProperty("bundletoolDownloadPath", System.getProperty("user.home") + "/.aab2apk"));
        } catch (IOException ex) {
            logger.error("Could not load settings", ex);
            bundletoolDownloadDir = new File(System.getProperty("user.home") + "/.aab2apk");
        }
    }

    @FXML
    private void onOpenSettings() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("settings-view.fxml"));
            Parent root = loader.load();

            Stage stage = new Stage();
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.setTitle("Settings");
            stage.setScene(new Scene(root));
            stage.showAndWait();

            // Reload settings after the settings window is closed
            loadSettings();
        } catch (IOException e) {
            logger.error("Error opening settings window", e);
        }
    }

    @FXML
    private void onSelectAABFile() {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Select AAB File");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Android App Bundle", "*.aab"));
        aabFile = fileChooser.showOpenDialog(null);
        if (aabFile != null) {
            aabFilePathField.setText(aabFile.getAbsolutePath());
            updateConvertButtonState();
        }
    }

    @FXML
    private void onSelectOutputDir() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("Select Output Directory");
        outputDir = directoryChooser.showDialog(null);
        if (outputDir != null) {
            outputDirPathField.setText(outputDir.getAbsolutePath());
            updateConvertButtonState();
        }
    }



    @FXML
    private void onSelectDeviceSpec() {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Select Device Spec JSON File");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JSON Files", "*.json"));
        deviceSpecFile = fileChooser.showOpenDialog(null);
        if (deviceSpecFile != null) {
            deviceSpecField.setText(deviceSpecFile.getAbsolutePath());
        }
    }

    @FXML
    private void onSelectKeystore() {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Select Keystore File");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Keystore Files", "*.jks", "*.keystore"));
        keystoreFile = fileChooser.showOpenDialog(null);
        if (keystoreFile != null) {
            keystorePathField.setText(keystoreFile.getAbsolutePath());
            loadKeyAliases(keystoreFile, keystorePasswordField.getText());
        }
    }

    private void loadKeyAliases(File keystoreFile, String keystorePassword) {
        keyAliasComboBox.getItems().clear();
        try {
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            try (InputStream is = new FileInputStream(keystoreFile)) {
                keystore.load(is, keystorePassword.toCharArray());
            }
            Enumeration<String> aliases = keystore.aliases();
            while (aliases.hasMoreElements()) {
                keyAliasComboBox.getItems().add(aliases.nextElement());
            }
            if (!keyAliasComboBox.getItems().isEmpty()) {
                keyAliasComboBox.setValue(keyAliasComboBox.getItems().get(0));
            }
        } catch (Exception e) {
            logger.error("Error loading key aliases", e);
            log("Error loading key aliases: " + e.getMessage());
        }
    }

    @FXML
    private void onConvert() {
        if (!checkAndDownloadBundletool()) {
            return;
        }

        progressBar.setProgress(0);
        logArea.clear();
        log("Starting conversion process...");

        new Thread(() -> {
            try {
                ProcessBuilder pb = new ProcessBuilder(
                        "java", "-jar", bundletoolJar.getAbsolutePath(),
                        "build-apks", "--bundle=" + aabFile.getAbsolutePath(),
                        "--output=" + outputDir.getAbsolutePath() + "/output.apks"
                );

                if (universalApkCheckBox.isSelected()) {
                    pb.command().add("--mode=universal");
                } else if (deviceSpecFile != null) {
                    pb.command().add("--device-spec=" + deviceSpecFile.getAbsolutePath());
                }

                if (keystoreFile != null && !keystorePathField.getText().isEmpty()) {
                    pb.command().add("--ks=" + keystorePathField.getText());
                    pb.command().add("--ks-pass=pass:" + keystorePasswordField.getText());
                    pb.command().add("--ks-key-alias=" + keyAliasComboBox.getValue());
                    pb.command().add("--key-pass=pass:" + keyPasswordField.getText());
                }

                Process process = pb.start();

                AtomicBoolean processFinished = new AtomicBoolean(false);
                Thread progressThread = new Thread(() -> {
                    while (!processFinished.get()) {
                        updateProgress();
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                });
                progressThread.start();

                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    final String logLine = line;
                    javafx.application.Platform.runLater(() -> log(logLine));
                }

                int exitCode = process.waitFor();
                processFinished.set(true);

                if (exitCode == 0) {
                    javafx.application.Platform.runLater(() -> {
                        log("Conversion completed successfully!");
                        progressBar.setProgress(1);
                    });
                } else {
                    javafx.application.Platform.runLater(() -> {
                        log("Conversion failed. Exit code: " + exitCode);
                        progressBar.setProgress(0);
                    });
                }
            } catch (IOException | InterruptedException e) {
                logger.error("Error during conversion", e);
                javafx.application.Platform.runLater(() -> {
                    log("Error: " + e.getMessage());
                    progressBar.setProgress(0);
                });
            }
        }).start();
    }

    private boolean checkAndDownloadBundletool() {
        String bundletoolVersion = bundletoolVersionComboBox.getValue();
        String bundletoolFileName = "bundletool-all-" + bundletoolVersion + ".jar";
        bundletoolJar = new File(bundletoolDownloadDir, bundletoolFileName);

        if (!bundletoolJar.exists()) {
            log("Downloading bundletool version " + bundletoolVersion + "...");
            progressBar.setProgress(ProgressBar.INDETERMINATE_PROGRESS);

            try {
                URL url = new URL("https://github.com/google/bundletool/releases/download/" + bundletoolVersion + "/" + bundletoolFileName);
                Path targetPath = bundletoolJar.toPath();
                Files.createDirectories(targetPath.getParent());
                Files.copy(url.openStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);

                log("bundletool downloaded successfully.");
                progressBar.setProgress(0);
                return true;
            } catch (IOException e) {
                logger.error("Failed to download bundletool", e);
                log("Failed to download bundletool: " + e.getMessage());
                progressBar.setProgress(0);
                return false;
            }
        }

        return true;
    }

    private void updateProgress() {
        javafx.application.Platform.runLater(() -> {
            double currentProgress = progressBar.getProgress();
            if (currentProgress < 0.9) {
                progressBar.setProgress(currentProgress + 0.01);
            }
        });
    }

    private void updateConvertButtonState() {
        convertButton.setDisable(aabFile == null || outputDir == null);
    }

    private void log(String message) {
        logger.info(message);
        logArea.appendText(message + "\n");
    }

    @FXML
    private void onClearLog() {
        logArea.clear();
        logger.info("Log cleared");
    }
}